package com.exmaple.MysqlMasterAndSlave;

import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Locale;
import java.util.Properties;

/**
 * @author Liuqz
 * @date 2018/12/22 15:35
 */
public class DynamicDataSourceInterceptor implements Interceptor {


    private static final String REGEX = ".*insert\\u0020.*|.*update\\u0020.*|.*delete\\u0020.*";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //判断是否为事务
        boolean synchronizationActive = TransactionSynchronizationManager.isActualTransactionActive();
        //获取参数
        Object[] objects = invocation.getArgs();
        //第一个参数代表是执行类型
        MappedStatement ms = (MappedStatement) objects[0];
        String lookupKey = DynamicDataSoucreHolder.DB_MASTER;

        //若不为事务
        if (!synchronizationActive) {
            //读方法
            if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {
                //selectKey 为自增id查询主键(SELECT LAST_INSERT_ID())方法,使用主库
                if (ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)) {
                    lookupKey = DynamicDataSoucreHolder.DB_MASTER;
                } else {
                    //第二个参数为执行的sql
                    BoundSql boundSql = ms.getSqlSource().getBoundSql(objects[1]);
                    String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll("[\\t\\n\\r]", "");
                    if (sql.matches(REGEX)) {
                        //增删改在主库
                        lookupKey = DynamicDataSoucreHolder.DB_MASTER;
                    } else {
                        //读在从库
                        lookupKey = DynamicDataSoucreHolder.DB_SLAVE;
                    }
                }
            }
        } else {
            lookupKey = DynamicDataSoucreHolder.DB_MASTER;
        }
        //设置使用的数据源
        DynamicDataSoucreHolder.setDbType(lookupKey);
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        /**
         * Executor为拦截所有的增删改查操作,然后决定使用intercept中的哪个数据源
         */
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
